package com.wg.core.script;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wg.game.GameConfig;

import java.util.ArrayList;
import java.util.List;

/**
 * 脚本管理器（单例模式，提供全局脚本访问入口）
 *
 * @author ChenLong
 */
public class ScriptManager {
    private static final Log log = LogFactory.get();
    /**
     * Java脚本文件后缀
     */
    private static final String JAVA_SUFFIX = ".java";
    /**
     * 脚本加载器
     */
    private final ScriptJavaLoader javaLoader = new ScriptJavaLoader();
    /**
     * 初始化状态（线程安全）
     */
    private volatile boolean initialized = false;

    private ScriptManager() {
       
    }

    /**
     * 获取单例实例
     */
    public static ScriptManager getInstance() {
        return Singleton.INSTANCE.getManager();
    }

    /**
     * 初始化脚本管理器（程序启动时调用，仅执行一次）
     */
    public void init() {
        if (initialized) {
            log.warn("ScriptManager already initialized");
            return;
        }

        synchronized (this) {
            if (initialized) {
                return;
            }

            String sourcePath = GameConfig.getInstance().getScriptSourcePath();
            if (StrUtil.isBlank(sourcePath)) {
                return;
            }

            try {
                javaLoader.initialize(sourcePath);
                javaLoader.loadScriptAll();
                initialized = true;
                log.info("ScriptManager initialized successfully");
            } catch (Exception e) {
                log.error("ScriptManager initialization failed", e);
            }
        }
    }

    /**
     * 调用脚本
     *
     * @param scriptName 脚本全类名
     * @param arg        参数容器
     * @return 执行结果
     * @throws Exception 执行异常（包括脚本未找到、初始化未完成等）
     */
    public Object call(String scriptName, ScriptArgs arg) throws Exception {
        if (!initialized) {
            throw new IllegalStateException("ScriptManager not initialized");
        }
        if (StrUtil.isBlank(scriptName)) {
            throw new IllegalArgumentException("script name cannot be null");
        }
        return javaLoader.call(scriptName, arg);
    }

    /**
     * 重新加载脚本（支持全类名或包名，逗号分隔）
     * <p>
     * 例："com.wg.TestScript,com.wg.user" 表示重载TestScript类和user包下所有脚本
     * </p>
     *
     * @param scripts 脚本名或包名列表
     */
    public void reloadScript(String scripts) {
        if (!initialized) {
            log.error("ScriptManager not initialized, cannot reload scripts");
            return;
        }
        if (StrUtil.isBlank(scripts)) {
            log.warn("Reload script parameter is empty");
            return;
        }

        List<String> scriptNames = new ArrayList<>();
        for (String item : scripts.split(",")) {
            item = item.trim();
            if (StrUtil.isBlank(item)) {
                continue;
            }
            // 若为包名，解析包下所有脚本；否则视为类名
            if (isPackage(item)) {
                scriptNames.addAll(javaLoader.parseFolderJavaFile(item));
            } else {
                scriptNames.add(item);
            }
        }

        if (!scriptNames.isEmpty()) {
            javaLoader.loadScript(scriptNames, true);
            log.info("Reloaded {} scripts successfully", scriptNames.size());
        } else {
            log.warn("No scripts found to reload: {}", scripts);
        }
    }

    /**
     * 判断是否为包名（简单规则：包名不含.java且通常包含多个.）
     */
    private boolean isPackage(String name) {
        return !name.endsWith(JAVA_SUFFIX) && name.contains(".");
    }

    private enum Singleton {
        INSTANCE;

        private final ScriptManager manager;

        Singleton() {
            manager = new ScriptManager();
        }

        ScriptManager getManager() {
            return manager;
        }
    }
}